/*=========================================================================
| KCardDAV
|--------------------------------------------------------------------------
| (c) 2010  Kumaran Santhanam
|
| This project is released under the GNU General Public License.
| Please see the file COPYING for more details.
|--------------------------------------------------------------------------
| Upload job class.
 ========================================================================*/

/*=========================================================================
| INCLUDES
 ========================================================================*/

#include "upload.h"
#include "resource.h"

#include <kabc/addresseelist.h>
#include <kabc/vcardconverter.h>

#include <kdebug.h>
#include <klocalizedstring.h>

#include <neon/ne_alloc.h>
#include <neon/ne_xml.h>

#include <QtCore/QByteArray>

#define log(s)      kDebug() << s;

/*=========================================================================
| NAMESPACE
 ========================================================================*/

using namespace KABC::carddav;

/*=========================================================================
| Impl
 ========================================================================*/

struct UploadJob::Impl {
	enum {
		actNone,
		actAdd,
		actEdit,
		actDel
	} last_action;

    UploadJob* owner;
    AddresseeList added;
    AddresseeList changed;
    AddresseeList deleted;
    int added_index;
    int changed_index;
	int deleted_index;

    static QByteArray addresseeString(const KABC::Addressee& a);

    QByteArray addresseePath(const KABC::Addressee& a) const;
    ne_request* createRequest(ne_session* session, const KABC::Addressee& a, const char *request);
};

QByteArray UploadJob::Impl::addresseeString(const KABC::Addressee& a) {
    VCardConverter c;
    return c.createVCard(a);
}

QByteArray UploadJob::Impl::addresseePath(const KABC::Addressee& a) const {
    QByteArray ret = owner->url().encodedPath();
    if (!ret.endsWith('/')) {
        ret.append('/');
    }
    ret.append(a.uid() + ".vcf");
    return ret;
}

ne_request* UploadJob::Impl::createRequest(ne_session* session, const KABC::Addressee& k_a, const char *request) {
    static QByteArray s_body;

    log("building request " << request);
    ne_request* ret = ne_request_create(session, request, addresseePath(k_a).constData());
    ne_add_request_header(ret, "If-None-Match", "*");
    ne_add_request_header(ret, "Content-Type", "text/vcard");
    s_body = addresseeString(k_a);
    // s_body is static because this method doesn't do copying.
    ne_set_request_body_buffer(ret, s_body.constData(), s_body.size());

    log("adressee path: " << QString(addresseePath(k_a)));
    log("adressee body:" << QString(s_body));
    return ret;
}

/*=========================================================================
| CONSTRUCTOR AND DESTRUCTOR
 ========================================================================*/

UploadJob::UploadJob(const QUrl& aUrl,
                     const AddresseeList& added,
                     const AddresseeList& changed,
                     const AddresseeList& deleted
                     )
    : Job(aUrl)
    , m_i(new Impl)
{
    m_i->owner = this;
    m_i->added = added;
    m_i->changed = changed;
    m_i->deleted = deleted;
    m_i->added_index = 0;
    m_i->changed_index = 0;
	m_i->deleted_index = 0;
	m_i->last_action = Impl::actNone;

	log("UploadJob constructed: " << added.size() << " to add, " << changed.size() << " to edit, " << deleted.size() << "to del");
}

UploadJob::~UploadJob() {
    delete m_i;
}


/*=========================================================================
| PUBLIC METHODS
 ========================================================================*/

/*=========================================================================
| PRIVATE METHODS
 ========================================================================*/

ne_request* UploadJob::createRequest(ne_session* session) {
    ne_request* ret = 0;
	if (m_i->added_index < m_i->added.size()) {
		m_i->last_action = Impl::actAdd;
        ret = m_i->createRequest(session, m_i->added[m_i->added_index], "PUT");
	} else if (m_i->changed_index < m_i->changed.size()) {
		m_i->last_action = Impl::actEdit;
        ret = m_i->createRequest(session, m_i->changed[m_i->changed_index], "PUT");
	} else if (m_i->deleted_index < m_i->deleted.size()) {
		m_i->last_action = Impl::actDel;
        ret = m_i->createRequest(session, m_i->deleted[m_i->deleted_index], "DELETE");
	}
    return ret;
}

bool UploadJob::requestAgain() {
    return m_i->added_index < m_i->added.size() || m_i->changed_index < m_i->changed.size() || m_i->deleted_index < m_i->deleted.size();
}

void UploadJob::blockRead(const char */*buf*/, size_t /*len*/) {
}

void UploadJob::requestFinished() {
	switch(m_i->last_action) {
		case Impl::actAdd:
			m_i->added_index++;
			break;
		case Impl::actEdit:
			m_i->changed_index++;
			break;
		case Impl::actDel:
			m_i->deleted_index++;
			break;
		default:
			break;
	}
	m_i->last_action = Impl::actNone;
}

void UploadJob::jobFinished(ResourceCardDav* customer) {
    if (customer->addedAddressees() == m_i->added &&
        customer->changedAddressees() == m_i->changed &&
        customer->deletedAddressees() == m_i->deleted)
    {
        customer->clearChanges();
    }
}

// EOF ========================================================================
